package org.chen.service.impl;

import com.alibaba.nacos.common.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.chen.domain.config.AvatarConfig;
import org.chen.domain.config.AvatarSegmentConfig;
import org.chen.domain.config.CommonVideoConfig;
import org.chen.domain.entity.*;
import org.chen.domain.vo.CategoryVO;
import org.chen.client.CategoryFeignClient;
import org.chen.client.HeyGenClient;
import org.chen.common.constant.ArticleStatusEnum;
import org.chen.common.constant.VideoStatusEnum;
import org.chen.common.exception.ServiceException;
import org.chen.common.utils.IdGenerator;
import org.chen.common.utils.SnowflakeIdGenerator;
import org.chen.domain.dto.*;
import org.chen.domain.response.PageResult;
import org.chen.domain.vo.TaskVO;
import org.chen.mapper.ArticleMapper;
import org.chen.mapper.TaskBackgroundMapper;
import org.chen.mapper.VideoTaskMapper;
import org.chen.produce.TaskMessageProducer;
import org.chen.service.VideoTaskService;
import org.chen.utils.VideoRedisUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class VideoTaskServiceImpl extends ServiceImpl<VideoTaskMapper, VideoTask> implements VideoTaskService {
    @Autowired
    private HeyGenClient heyGenClient;

    @Autowired
    private VideoTaskMapper taskMapper;

    @Autowired
    private ArticleMapper articleMapper;

    @Autowired
    private TaskMessageProducer taskMessageProducer;

    @Autowired
    private CategoryFeignClient categoryFeignClient;

    @Autowired
    private TaskBackgroundMapper taskBackgroundMapper;

    @Autowired
    private VideoRedisUtils videoRedisUtils;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> createTasks(BatchGenerateDTO generateDTO) {
        // 1. 快速创建任务记录
        List<VideoTask> tasks = new ArrayList<>();
        List<String> articleIds = generateDTO.getArticleIds();

        // 批量查询文章信息
        List<VideoArticle> articles = articleMapper.selectBatchIds(articleIds);
        Map<String, VideoArticle> articleMap = articles.stream()
                .collect(Collectors.toMap(VideoArticle::getId, a -> a));

        for (String articleId : articleIds) {
            VideoArticle article = articleMap.get(articleId);
            if (article == null || ArticleStatusEnum.COMPLETED.getCode().equals(article.getStatus())) {
                continue;
            }

            // 创建任务
            VideoTask task = createTask(article, generateDTO.getConfig());
            tasks.add(task);

            // 更新文章状态
            article.setStatus(ArticleStatusEnum.PROCESSING.getCode());
        }

        // 2. 批量保存任务和更新文章状态
        if (!tasks.isEmpty()) {
            taskMapper.batchInsert(tasks);
            articleMapper.batchUpdateStatus(articleIds, ArticleStatusEnum.PROCESSING.getCode());
        }

        // 3. 异步发送任务消息
        List<MessageData> messageDataList = tasks.stream()
                .map(task -> {
                    MessageData messageData = new MessageData();
                    messageData.setVideoTask(task);
                    messageData.setUserVideoConfig(generateDTO.getConfig());
                    return messageData;
                })
                .toList();
        taskMessageProducer.batchSendTaskMessages(messageDataList);

        return tasks.stream()
                .map(VideoTask::getId)
                .collect(Collectors.toList());
    }

    private VideoTask createTask(VideoArticle article, UserVideoConfig config) {
        VideoTask task = new VideoTask();
        task.setId(SnowflakeIdGenerator.nextId());
        task.setArticleId(article.getId());
        if (config.getId() != null) {
            task.setConfigId(config.getId());
        }
        task.setWidth(config.getWidth());
        task.setHeight(config.getHeight());
        task.setCategoryId(article.getCategoryId());
        task.setCategoryPath(article.getCategoryPath());
        task.setCategory(article.getCategory());
        task.setCaption(config.getIsCaption());
        task.setCallbackId(IdGenerator.generateCallbackId());
        task.setTitle(article.getTitle());
        task.setDescription(article.getDescription());
        task.setAvatarId(config.getAvatarId());
        task.setVoiceId(config.getVoiceId());
        task.setStatus(VideoStatusEnum.PENDING.getCode());
        task.setCreateTime(LocalDateTime.now());
        task.setUpdateTime(LocalDateTime.now());

        TaskBackground taskBackground = new TaskBackground();
        taskBackground.setId(SnowflakeIdGenerator.nextId());
        taskBackground.setBackgroundColor(config.getBackgroundColor());
        taskBackground.setBackgroundFit(config.getBackgroundFit());
        taskBackground.setBackgroundType(config.getBackgroundType());
        taskBackground.setBackgroundUrl(config.getBackgroundUrl());
        taskBackground.setBackgroundId(config.getBackgroundId());
        taskBackground.setBackgroundPlayStyle(config.getBackgroundPlayStyle());
        taskBackground.setScale(config.getScale());
        taskBackground.setYOffset(config.getYOffset());
        taskBackground.setXOffset(config.getXOffset());

        taskBackgroundMapper.insert(taskBackground);

        task.setBackgroundId(taskBackground.getId());

        return task;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void handleCallback(VideoCallbackDTO callback) {
        VideoTask task = taskMapper.selectByCallbackId(callback.getEvent_data().getCallback_id());
        if (task == null) {
            log.warn("No task found for callback_id: {}", callback.getEvent_data().getCallback_id());
            return;
        }

        String eventType = callback.getEvent_type();
        VideoCallbackDTO.EventData eventData = callback.getEvent_data();

        switch (eventType) {
            case "avatar_video.success":
                // 更新视频URL
                task.setVideoUrl(eventData.getUrl());
                // 只有在收到视频回调时才更新完成状态
                task.setStatus(VideoStatusEnum.COMPLETED.getCode());
                // 如果是多数字人模式，检查任务组
                if (Boolean.TRUE.equals(task.getIsMultiAvatar()) && task.getTaskGroupId() != null) {
                    // 标记当前任务已完成
                    videoRedisUtils.markTaskCompleted(task.getTaskGroupId(), task.getId());

                    // 检查任务组中是否所有任务都已完成
                    if (videoRedisUtils.isTaskGroupCompleted(task.getTaskGroupId())) {
                        // 所有数字人任务都已完成，更新文章状态
                        articleMapper.updateStatus(task.getArticleId(), ArticleStatusEnum.COMPLETED.getCode());
                    }
                } else {
                    // 单数字人模式，直接更新文章状态
                    articleMapper.updateStatus(task.getArticleId(), ArticleStatusEnum.COMPLETED.getCode());
                }
                break;

            case "avatar_video_gif.success":
                // 更新GIF URL
                task.setGifUrl(eventData.getUrl());
                break;

            case "avatar_video.fail":
                // 只有在收到视频回调时才更新完成状态
                task.setStatus(VideoStatusEnum.FAILED.getCode());
                task.setErrorMessage(eventData.getMsg());
                // 如果是多数字人模式，标记当前任务失败
                if (Boolean.TRUE.equals(task.getIsMultiAvatar()) && task.getTaskGroupId() != null) {
                    videoRedisUtils.markTaskFailed(task.getTaskGroupId(), task.getId());

                    // 检查是否所有任务都已完成或失败
                    if (videoRedisUtils.isTaskGroupFinished(task.getTaskGroupId())) {
                        // 更新文章状态，如果所有任务都失败则文章状态也失败
                        if (videoRedisUtils.hasCompletedTask(task.getTaskGroupId())) {
                            articleMapper.updateStatus(task.getArticleId(), ArticleStatusEnum.COMPLETED.getCode());
                        } else {
                            articleMapper.updateStatus(task.getArticleId(), ArticleStatusEnum.FAILED.getCode());
                        }
                    }
                } else {
                    // 单数字人模式，直接更新文章状态
                    articleMapper.updateStatus(task.getArticleId(), ArticleStatusEnum.FAILED.getCode());
                }
                break;

            default:
                task.setStatus(VideoStatusEnum.FAILED.getCode());
                task.setErrorMessage("视频生成失败");
                articleMapper.updateStatus(task.getArticleId(), ArticleStatusEnum.FAILED.getCode());
                break;
        }

        taskMapper.updateById(task);
    }

    @Override
    public PageResult<TaskVO> getTaskList(TaskQueryDTO query) {
        Page<VideoTask> page = new Page<>(query.getPageNum(), query.getPageSize());

        LambdaQueryWrapper<VideoTask> wrapper = new LambdaQueryWrapper<VideoTask>()
                .like(StringUtils.isNotBlank(query.getTitle()), VideoTask::getTitle, query.getTitle())
                .eq(query.getStatus() != null, VideoTask::getStatus, query.getStatus())
                .ge(query.getStartTime() != null, VideoTask::getCreateTime, query.getStartTime())
                .eq(StringUtils.isNotBlank(query.getCategoryId()), VideoTask::getCategoryId, query.getCategoryId())
                .le(query.getEndTime() != null, VideoTask::getCreateTime, query.getEndTime())
                .orderByDesc(VideoTask::getCreateTime);

        // 查询任务列表
        Page<VideoTask> videoTaskPage = taskMapper.selectPage(page, wrapper);

        // 获取所有分类ID
        Set<String> categoryIds = videoTaskPage.getRecords().stream()
                .map(VideoTask::getCategoryId)
                .filter(Objects::nonNull)
                .collect(Collectors.toSet());

        // 批量获取分类信息
        Map<String, CategoryVO> categoryMap = new HashMap<>();
        if (!categoryIds.isEmpty()) {
            try {
                List<CategoryVO> categories = categoryFeignClient.getCategoriesByIds(new ArrayList<>(categoryIds)).getData();
                categoryMap = categories.stream()
                        .collect(Collectors.toMap(CategoryVO::getId, category -> category));
            } catch (Exception e) {
                log.error("Failed to get categories", e);
            }
        }

        // 转换为VO
        Map<String, CategoryVO> finalCategoryMap = categoryMap;
        List<TaskVO> taskVOs = videoTaskPage.getRecords().stream()
                .map(task -> convertToVO(task, finalCategoryMap.get(task.getCategoryId())))
                .collect(Collectors.toList());

        return new PageResult<>(
                taskVOs,
                page.getTotal(),
                page.getSize(),
                page.getCurrent()
        );
    }

    /**
     * 重试单个任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void retryTask(String taskId) {
        VideoTask task = taskMapper.selectById(taskId);
        if (task == null) {
            throw new ServiceException("任务不存在");
        }

        if (!VideoStatusEnum.FAILED.getCode().equals(task.getStatus())) {
            throw new ServiceException("只能重试失败的任务");
        }

        // 更新任务状态
        task.setStatus(VideoStatusEnum.PENDING.getCode());
        task.setErrorMessage("");
        task.setCallbackId(IdGenerator.generateCallbackId());
        taskMapper.updateById(task);

        // 准备消息数据
        MessageData messageData = new MessageData();
        messageData.setVideoTask(task);

        // 设置模式
        if (Boolean.TRUE.equals(task.getIsMultiAvatar())) {
            messageData.setMode("multiple");
        } else {
            messageData.setMode("single");
        }

        // 获取配置信息
        if (task.getBackgroundId() != null) {
            UserVideoConfig config = createConfigFromBackground(task);
            messageData.setUserVideoConfig(config);
        }

        // 发送消息
        taskMessageProducer.sendTaskMessage(messageData);

        // 如果是多数字人模式的任务，更新Redis中的任务组信息
        if (Boolean.TRUE.equals(task.getIsMultiAvatar()) && task.getTaskGroupId() != null) {
            // 清除之前的完成/失败状态
            videoRedisUtils.clearTaskStatus(task.getTaskGroupId(), task.getId());
            // 确保任务在任务组中
            videoRedisUtils.addTaskToGroup(task.getTaskGroupId(), task.getId());
        }
    }

    private TaskVO convertToVO(VideoTask task, CategoryVO category) {
        TaskVO vo = new TaskVO();
        BeanUtils.copyProperties(task, vo);
        vo.setStatus(VideoStatusEnum.getDesc(task.getStatus()));
        vo.setCreateTime(task.getCreateTime().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        // 设置分类信息
        if (category != null) {
            vo.setCategoryName(category.getName());
        }

        return vo;
    }

    @Override
    public void downloadVideos(List<String> taskIds, OutputStream outputStream) throws IOException {
        try (ZipOutputStream zipOut = new ZipOutputStream(outputStream)) {
            // 使用压缩以减小文件大小
            zipOut.setLevel(Deflater.BEST_SPEED);  // 速度和大小的权衡

            // 创建一个线程池
            ExecutorService executorService = Executors.newFixedThreadPool(
                    Math.min(5, taskIds.size())); // 最多5个并行线程

            // 用于收集每个视频的数据
            Map<String, Future<VideoDownloadResult>> downloadFutures = new ConcurrentHashMap<>();

            // 提交下载任务
            for (String taskId : taskIds) {
                Future<VideoDownloadResult> future = executorService.submit(() -> {
                    VideoTask task = taskMapper.selectById(taskId);
                    if (task == null || !VideoStatusEnum.COMPLETED.getCode().equals(task.getStatus())) {
                        log.warn("Skip invalid task: {}", taskId);
                        return null;
                    }

                    try {
                        ByteArrayOutputStream bass = getByteArrayOutputStream(task);

                        String fileName = task.getTitle().replaceAll("[\\\\/:*?\"<>|]", "_") + ".mp4";
                        return new VideoDownloadResult(fileName, bass.toByteArray());
                    } catch (Exception e) {
                        log.error("Download video failed for task: {}", taskId, e);
                        return null;
                    }
                });

                downloadFutures.put(taskId, future);
            }

            // 等待所有下载完成并写入ZIP
            int successCount = 0;
            for (String taskId : taskIds) {
                try {
                    Future<VideoDownloadResult> future = downloadFutures.get(taskId);
                    VideoDownloadResult result = future.get(120, TimeUnit.SECONDS); // 设置超时

                    if (result != null) {
                        ZipEntry zipEntry = new ZipEntry(result.fileName());
                        zipOut.putNextEntry(zipEntry);
                        zipOut.write(result.data());
                        zipOut.closeEntry();
                        successCount++;
                    }
                } catch (Exception e) {
                    log.error("Failed to process download result for task: {}", taskId, e);
                }
            }

            executorService.shutdown();

            if (successCount == 0) {
                throw new ServiceException("没有成功下载任何视频");
            }
        }
    }

    @NotNull
    private static ByteArrayOutputStream getByteArrayOutputStream(VideoTask task) throws IOException {
        URL url = new URL(task.getVideoUrl());
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setConnectTimeout(15000);
        conn.setReadTimeout(30000);

        // 读取到内存缓冲
        ByteArrayOutputStream bass = new ByteArrayOutputStream();
        try (InputStream videoStream = conn.getInputStream()) {
            byte[] buffer = new byte[16384]; // 更大的缓冲区
            int length;
            while ((length = videoStream.read(buffer)) >= 0) {
                bass.write(buffer, 0, length);
            }
        }
        return bass;
    }

    // 帮助类，存储下载结果
    private record VideoDownloadResult(String fileName, byte[] data) {

    }

    @Override
    public void deleteTask(String id) {
        // 检查视频状态
        VideoTask videoTask = taskMapper.selectById(id);
        if (videoTask == null) {
            throw new ServiceException("视频不存在");
        }

        // 删除任务
        taskMapper.deleteById(id);

        // 如果是多数字人模式，检查是否需要删除文章
        if (Boolean.TRUE.equals(videoTask.getIsMultiAvatar()) && videoTask.getTaskGroupId() != null) {
            // 查询同组的其他任务数量
            Long count = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                    .eq(VideoTask::getTaskGroupId, videoTask.getTaskGroupId()));

            // 如果没有其他任务，则删除文章
            if (count == 0) {
                articleMapper.deleteById(videoTask.getArticleId());
            }
        } else {
            // 单数字人模式，直接删除文章
            articleMapper.deleteById(videoTask.getArticleId());
        }

        // 删除远程视频
        if (videoTask.getVideoId() != null) {
            try {
                heyGenClient.deleteRemoteVideo(videoTask.getVideoId(), videoTask.getApiKey());
            } catch (Exception e) {
                log.warn("删除远程视频失败: {}, {}", videoTask.getVideoId(), e.getMessage());
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<String> ids) {
        // 检查视频状态
        List<VideoTask> videoTasks = taskMapper.selectBatchIds(ids);

        // 按任务组分组（针对多数字人模式）
        Map<String, List<VideoTask>> taskGroups = videoTasks.stream()
                .filter(task -> task.getTaskGroupId() != null)
                .collect(Collectors.groupingBy(VideoTask::getTaskGroupId));

        // 非任务组任务（单数字人模式或旧版任务）
        List<VideoTask> nonGroupTasks = videoTasks.stream()
                .filter(task -> task.getTaskGroupId() == null)
                .toList();

        // 删除远程视频
        for (VideoTask videoTask : videoTasks) {
            if (videoTask.getVideoId() != null) {
                try {
                    heyGenClient.deleteRemoteVideo(videoTask.getVideoId(), videoTask.getApiKey());
                } catch (Exception e) {
                    log.warn("删除远程视频失败: {}, {}", videoTask.getVideoId(), e.getMessage());
                }
            }
        }

        // 批量删除任务
        taskMapper.deleteByIds(ids);

        // 处理文章删除
        Set<String> articlesToDelete = new HashSet<>();

        // 对于任务组，检查是否需要删除文章
        for (String groupId : taskGroups.keySet()) {
            // 查询同组的其他任务数量
            Long count = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                    .eq(VideoTask::getTaskGroupId, groupId));

            // 如果没有其他任务，则删除文章
            if (count == 0) {
                String articleId = taskGroups.get(groupId).get(0).getArticleId();
                articlesToDelete.add(articleId);
            }
        }

        // 对于非任务组任务，直接添加到删除列表
        for (VideoTask task : nonGroupTasks) {
            articlesToDelete.add(task.getArticleId());
        }

        // 批量删除文章
        if (!articlesToDelete.isEmpty()) {
            articleMapper.deleteByIds(new ArrayList<>(articlesToDelete));
        }
    }

    @Override
    public VideoStatisticsDTO getStatistics() {
        LocalDateTime today = LocalDate.now().atStartOfDay();
        LocalDateTime weekStart = today.minusWeeks(1);

        // 统计总数
        Long totalVideos = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .eq(VideoTask::getStatus, VideoStatusEnum.COMPLETED.getCode()));

        // 任务统计
        Long totalTasks = taskMapper.selectCount(null);
        Long processingTasks = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .in(VideoTask::getStatus, Arrays.asList(
                        VideoStatusEnum.PENDING.getCode(),
                        VideoStatusEnum.GENERATING.getCode()
                )));
        Long completedTasks = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .eq(VideoTask::getStatus, VideoStatusEnum.COMPLETED.getCode()));
        Long failedTasks = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .eq(VideoTask::getStatus, VideoStatusEnum.FAILED.getCode()));

        // 今日统计
        Long todayVideos = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .eq(VideoTask::getStatus, VideoStatusEnum.COMPLETED.getCode())
                .ge(VideoTask::getCreateTime, today));
        Long todayTasks = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .ge(VideoTask::getCreateTime, today));

        // 本周统计
        Long weekVideos = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .eq(VideoTask::getStatus, VideoStatusEnum.COMPLETED.getCode())
                .ge(VideoTask::getCreateTime, weekStart));
        Long weekTasks = taskMapper.selectCount(new LambdaQueryWrapper<VideoTask>()
                .ge(VideoTask::getCreateTime, weekStart));

        return VideoStatisticsDTO.builder()
                .totalVideos(totalVideos)
                .totalTasks(totalTasks)
                .processingTasks(processingTasks)
                .completedTasks(completedTasks)
                .failedTasks(failedTasks)
                .todayVideos(todayVideos)
                .todayTasks(todayTasks)
                .weekVideos(weekVideos)
                .weekTasks(weekTasks)
                .build();
    }

    @Override
    public List<TaskVO> getRecentTasks(int limit) {
        // 获取最近的任务列表
        List<VideoTask> tasks = taskMapper.selectList(new LambdaQueryWrapper<VideoTask>()
                .orderByDesc(VideoTask::getCreateTime)
                .last("LIMIT " + limit));

        // 转换为VO
        return tasks.stream()
                .map(task -> {
                    TaskVO vo = new TaskVO();
                    vo.setTitle(task.getTitle());
                    vo.setStatus(VideoStatusEnum.getDesc(task.getStatus()));
                    // 格式化创建时间
                    vo.setCreateTime(task.getCreateTime().format(
                            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
                    return vo;
                })
                .collect(Collectors.toList());
    }

    @Override
    public Map<String, Integer> getTaskTrend(LocalDateTime startTime, LocalDateTime endTime) {
        // 获取时间段内的所有任务
        List<VideoTask> tasks = taskMapper.selectList(new LambdaQueryWrapper<VideoTask>()
                .between(VideoTask::getCreateTime, startTime, endTime));

        // 计算各种状态的任务数量
        int total = tasks.size();
        int completed = (int) tasks.stream()
                .filter(task -> VideoStatusEnum.COMPLETED.getCode().equals(task.getStatus()))
                .count();
        int processing = (int) tasks.stream()
                .filter(task -> VideoStatusEnum.GENERATING.getCode().equals(task.getStatus()) ||
                        VideoStatusEnum.PENDING.getCode().equals(task.getStatus()))
                .count();
        int failed = (int) tasks.stream()
                .filter(task -> VideoStatusEnum.FAILED.getCode().equals(task.getStatus()))
                .count();

        // 同期比较（上一个相同时间段）
        LocalDateTime previousStartTime = startTime.minus(Duration.between(startTime, endTime));
        List<VideoTask> previousTasks = taskMapper.selectList(new LambdaQueryWrapper<VideoTask>()
                .between(VideoTask::getCreateTime, previousStartTime, startTime));
        int previousTotal = previousTasks.size();

        return Map.of(
                "total", total,
                "completed", completed,
                "processing", processing,
                "failed", failed,
                "previousTotal", previousTotal
        );
    }

    /**
     * 批量重试任务
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchRetryTasks(List<String> taskIds) {
        if (taskIds == null || taskIds.isEmpty()) {
            throw new ServiceException("任务ID列表不能为空");
        }

        // 查询所有任务
        List<VideoTask> tasks = taskMapper.selectBatchIds(taskIds);

        // 筛选出失败的任务
        List<VideoTask> failedTasks = tasks.stream()
                .filter(task -> VideoStatusEnum.FAILED.getCode().equals(task.getStatus()))
                .toList();

        if (failedTasks.isEmpty()) {
            throw new ServiceException("没有找到可重试的失败任务");
        }

        // 按任务组ID分组（针对多数字人模式）
        Map<String, List<VideoTask>> taskGroups = failedTasks.stream()
                .filter(task -> task.getTaskGroupId() != null)
                .collect(Collectors.groupingBy(VideoTask::getTaskGroupId));

        // 非任务组任务（单数字人模式或旧版任务）
        List<VideoTask> nonGroupTasks = failedTasks.stream()
                .filter(task -> task.getTaskGroupId() == null)
                .toList();

        // 批量更新任务状态
        for (VideoTask task : failedTasks) {
            task.setStatus(VideoStatusEnum.PENDING.getCode());
            task.setErrorMessage("");
            task.setCallbackId(IdGenerator.generateCallbackId());
        }

        // 批量更新数据库
        this.updateBatchById(failedTasks);

        // 准备消息数据并发送
        List<MessageData> messageDataList = new ArrayList<>();

        // 处理任务组任务（多数字人模式）
        for (String groupId : taskGroups.keySet()) {
            List<VideoTask> groupTasks = taskGroups.get(groupId);

            for (VideoTask task : groupTasks) {
                MessageData messageData = new MessageData();
                messageData.setVideoTask(task);
                messageData.setMode("multiple");

                // 获取配置信息
                if (task.getBackgroundId() != null) {
                    UserVideoConfig config = createConfigFromBackground(task);
                    messageData.setUserVideoConfig(config);
                }

                messageDataList.add(messageData);

                // 清除之前的完成/失败状态
                videoRedisUtils.clearTaskStatus(groupId, task.getId());
                // 确保任务在任务组中
                videoRedisUtils.addTaskToGroup(groupId, task.getId());
            }
        }

        // 处理非任务组任务（单数字人模式或旧版任务）
        for (VideoTask task : nonGroupTasks) {
            MessageData messageData = new MessageData();
            messageData.setVideoTask(task);
            messageData.setMode("single");

            // 获取配置信息
            if (task.getBackgroundId() != null) {
                UserVideoConfig config = createConfigFromBackground(task);
                messageData.setUserVideoConfig(config);
            }

            messageDataList.add(messageData);
        }

        // 发送到消息队列
        taskMessageProducer.batchSendTaskMessages(messageDataList);

        log.info("批量重试任务成功，共 {} 个任务", failedTasks.size());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> createMultiAvatarTasks(BatchMultiAvatarGenerateDTO generateDTO) {
        List<String> allTaskIds = new ArrayList<>();
        List<String> articleIds = generateDTO.getArticleIds();
        CommonVideoConfig commonConfig = generateDTO.getCommonConfig();
        List<AvatarConfig> avatarConfigs = generateDTO.getAvatarConfigs();

        // 验证必要参数
        if (commonConfig == null) {
            throw new ServiceException("公共配置不能为空");
        }

        if (avatarConfigs == null || avatarConfigs.isEmpty()) {
            throw new ServiceException("数字人配置不能为空");
        }

        // 检查是否为一对一模式
        boolean isOneToOne = commonConfig.getOne_to_one() != null && commonConfig.getOne_to_one();

        // 一对一模式下，检查文章数量与数字人配置数量是否一致
        if (isOneToOne && articleIds.size() != avatarConfigs.size()) {
            throw new ServiceException("一对一模式下，文章数量必须与数字人配置数量一致");
        }

        // 批量查询文章信息
        List<VideoArticle> articles = articleMapper.selectBatchIds(articleIds);
        Map<String, VideoArticle> articleMap = articles.stream()
                .collect(Collectors.toMap(VideoArticle::getId, a -> a));

        if (isOneToOne) {
            // 一对一模式：每篇文章对应一个数字人
            for (int i = 0; i < articleIds.size(); i++) {
                String articleId = articleIds.get(i);
                AvatarConfig avatarConfig = avatarConfigs.get(i);

                VideoArticle article = articleMap.get(articleId);
                if (article == null || ArticleStatusEnum.COMPLETED.getCode().equals(article.getStatus())) {
                    continue;
                }

                // 创建任务组ID（每篇文章对应一个任务组）
                String taskGroupId = SnowflakeIdGenerator.nextId();

                // 创建背景配置
                TaskBackground taskBackground = createTaskBackground(commonConfig, avatarConfig, i);
                taskBackgroundMapper.insert(taskBackground);

                // 创建任务
                VideoTask task = new VideoTask();
                task.setId(SnowflakeIdGenerator.nextId());
                task.setArticleId(article.getId());
                task.setWidth(commonConfig.getWidth());
                task.setHeight(commonConfig.getHeight());
                task.setCategoryId(article.getCategoryId());
                task.setCategoryPath(article.getCategoryPath());
                task.setCategory(article.getCategory());
                task.setCaption(commonConfig.getIsCaption());
                task.setCallbackId(IdGenerator.generateCallbackId());
                task.setTitle(article.getTitle());
                task.setDescription(article.getDescription());
                task.setAvatarId(avatarConfig.getAvatarId());
                task.setVoiceId(avatarConfig.getVoiceId());
                task.setBackgroundId(taskBackground.getId());
                task.setStatus(VideoStatusEnum.PENDING.getCode());
                task.setCreateTime(LocalDateTime.now());
                task.setUpdateTime(LocalDateTime.now());
                task.setTaskGroupId(taskGroupId);
                task.setIsMultiAvatar(false); // 一对一模式
                task.setAvatarIndex(0); // 只有一个数字人，索引为0

                // 保存任务
                taskMapper.insert(task);

                // 更新文章状态
                article.setStatus(ArticleStatusEnum.PROCESSING.getCode());
                articleMapper.updateById(article);

                // 收集任务ID
                allTaskIds.add(task.getId());

                // 异步发送任务消息
                MessageData messageData = new MessageData();
                messageData.setVideoTask(task);
                messageData.setMode("single");

                // 获取背景信息并设置配置
                TaskBackground background = taskBackgroundMapper.selectById(task.getBackgroundId());
                UserVideoConfig userVideoConfig = createUserVideoConfig(commonConfig, background);
                messageData.setUserVideoConfig(userVideoConfig);

                taskMessageProducer.sendTaskMessage(messageData);
            }
        } else {
            // 多对一模式：每篇文章对应多个数字人（原有逻辑）
            for (String articleId : articleIds) {
                VideoArticle article = articleMap.get(articleId);
                if (article == null || ArticleStatusEnum.COMPLETED.getCode().equals(article.getStatus())) {
                    continue;
                }

                // 创建任务组ID（用于标识同一篇文章的多个数字人任务）
                String taskGroupId = SnowflakeIdGenerator.nextId();
                List<VideoTask> taskGroup = new ArrayList<>();

                // 为每个数字人创建一个任务
                for (int i = 0; i < avatarConfigs.size(); i++) {
                    AvatarConfig avatarConfig = avatarConfigs.get(i);

                    // 创建背景配置
                    TaskBackground taskBackground = createTaskBackground(commonConfig, avatarConfig, i);
                    taskBackgroundMapper.insert(taskBackground);

                    // 创建任务
                    VideoTask task = new VideoTask();
                    task.setId(SnowflakeIdGenerator.nextId());
                    task.setArticleId(article.getId());
                    task.setWidth(commonConfig.getWidth());
                    task.setHeight(commonConfig.getHeight());
                    task.setCategoryId(article.getCategoryId());
                    task.setCategoryPath(article.getCategoryPath());
                    task.setCategory(article.getCategory());
                    task.setCaption(commonConfig.getIsCaption());
                    task.setCallbackId(IdGenerator.generateCallbackId());

                    // 设置任务标题，添加数字人序号以区分
                    task.setTitle(article.getTitle() + " - 数字人" + (i + 1));
                    task.setDescription(article.getDescription());
                    task.setAvatarId(avatarConfig.getAvatarId());
                    task.setVoiceId(avatarConfig.getVoiceId());
                    task.setBackgroundId(taskBackground.getId());
                    task.setStatus(VideoStatusEnum.PENDING.getCode());
                    task.setCreateTime(LocalDateTime.now());
                    task.setUpdateTime(LocalDateTime.now());
                    task.setTaskGroupId(taskGroupId); // 记录任务组ID
                    task.setIsMultiAvatar(true); // 标记为多数字人模式
                    task.setAvatarIndex(i); // 记录数字人序号

                    taskGroup.add(task);
                }

                // 批量保存任务
                taskMapper.batchInsert(taskGroup);

                // 更新文章状态
                article.setStatus(ArticleStatusEnum.PROCESSING.getCode());
                articleMapper.updateById(article);

                // 收集任务ID
                List<String> taskIds = taskGroup.stream()
                        .map(VideoTask::getId)
                        .toList();
                allTaskIds.addAll(taskIds);

                // 异步发送任务消息
                List<MessageData> messageDataList = taskGroup.stream()
                        .map(task -> {
                            MessageData messageData = new MessageData();
                            messageData.setVideoTask(task);
                            messageData.setMode("multiple");

                            // 根据任务的背景ID查询背景信息
                            TaskBackground background = taskBackgroundMapper.selectById(task.getBackgroundId());

                            // 创建并设置UserVideoConfig
                            UserVideoConfig userVideoConfig = createUserVideoConfig(commonConfig, background);
                            messageData.setUserVideoConfig(userVideoConfig);
                            return messageData;
                        })
                        .toList();

                taskMessageProducer.batchSendTaskMessages(messageDataList);
            }
        }

        return allTaskIds;
    }

    private TaskBackground createTaskBackground(CommonVideoConfig commonConfig, AvatarConfig avatarConfig, int index) {
        log.info(commonConfig.toString());
        log.info(avatarConfig.toString());
        TaskBackground background = new TaskBackground();
        background.setId(SnowflakeIdGenerator.nextId());
        background.setBackgroundType(commonConfig.getBackgroundType());
        background.setBackgroundFit(commonConfig.getBackgroundFit());
        background.setBackgroundPlayStyle(commonConfig.getBackgroundPlayStyle());

        // 根据背景类型不同处理
        if ("color".equals(commonConfig.getBackgroundType())) {
            // 颜色背景直接使用
            background.setBackgroundColor(commonConfig.getBackgroundColor());
        } else if ("image".equals(commonConfig.getBackgroundType()) || "video".equals(commonConfig.getBackgroundType())) {
            // 处理图片/视频背景
            if (commonConfig.getBackgroundUrls() != null && !commonConfig.getBackgroundUrls().isEmpty()) {
                // 使用多背景模式
                int backgroundIndex = index % commonConfig.getBackgroundUrls().size(); // 循环使用背景
                background.setBackgroundUrl(commonConfig.getBackgroundUrls().get(backgroundIndex));

                // 如果有对应的背景ID，也设置
                if (commonConfig.getBackgroundIds() != null &&
                        !commonConfig.getBackgroundIds().isEmpty() &&
                        backgroundIndex < commonConfig.getBackgroundIds().size()) {
                    background.setBackgroundId(commonConfig.getBackgroundIds().get(backgroundIndex));
                }
            } else {
                // 兼容旧版，使用单一背景
                background.setBackgroundUrl(commonConfig.getBackgroundUrl());
                background.setBackgroundId(commonConfig.getBackgroundId());
            }
        }

        // 设置数字人特定的偏移和缩放
        background.setXOffset(avatarConfig.getXOffset());
        background.setYOffset(avatarConfig.getYOffset());
        background.setScale(avatarConfig.getScale());

        return background;
    }

    // 抽取公共方法：创建UserVideoConfig
    private UserVideoConfig createUserVideoConfig(CommonVideoConfig commonConfig, TaskBackground background) {
        UserVideoConfig userVideoConfig = new UserVideoConfig();
        userVideoConfig.setBackgroundType(background.getBackgroundType());
        userVideoConfig.setBackgroundId(background.getBackgroundId());
        userVideoConfig.setBackgroundColor(background.getBackgroundColor());
        userVideoConfig.setBackgroundUrl(background.getBackgroundUrl());
        userVideoConfig.setBackgroundFit(background.getBackgroundFit());
        userVideoConfig.setBackgroundPlayStyle(background.getBackgroundPlayStyle());
        userVideoConfig.setWidth(commonConfig.getWidth());
        userVideoConfig.setHeight(commonConfig.getHeight());
        userVideoConfig.setIsCaption(commonConfig.getIsCaption());
        userVideoConfig.setXOffset(background.getXOffset());
        userVideoConfig.setYOffset(background.getYOffset());
        userVideoConfig.setScale(background.getScale());
        return userVideoConfig;
    }

    /**
     * 根据背景ID创建新的用户视频配置
     */
    private UserVideoConfig createConfigFromBackground(VideoTask videoTask) {
        TaskBackground taskBackground = taskBackgroundMapper.selectById(videoTask.getBackgroundId());
        if (taskBackground == null) {
            throw new ServiceException("找不到指定的背景，背景ID: " + videoTask.getBackgroundId());
        }

        UserVideoConfig userVideoConfig = new UserVideoConfig();
        userVideoConfig.setWidth(videoTask.getWidth());
        userVideoConfig.setHeight(videoTask.getHeight());
        userVideoConfig.setIsCaption(videoTask.getCaption());
        userVideoConfig.setBackgroundType(taskBackground.getBackgroundType());

        // 根据背景类型设置属性
        if ("image".equals(taskBackground.getBackgroundType()) ||
                "video".equals(taskBackground.getBackgroundType())) {

            // 设置背景URL或ID
            if (taskBackground.getBackgroundId() == null || taskBackground.getBackgroundId().isEmpty()) {
                userVideoConfig.setBackgroundUrl(taskBackground.getBackgroundUrl());
            } else {
                userVideoConfig.setBackgroundId(taskBackground.getBackgroundId());
            }

            userVideoConfig.setBackgroundFit(taskBackground.getBackgroundFit());

            // 视频类型特有属性
            if ("video".equals(taskBackground.getBackgroundType())) {
                userVideoConfig.setBackgroundPlayStyle(taskBackground.getBackgroundPlayStyle());
            }
        } else {
            // 纯色背景
            userVideoConfig.setBackgroundColor(taskBackground.getBackgroundColor());
        }

        return userVideoConfig;
    }

}